package com.forest.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.forest.config.SignatureProperties;
import com.forest.constants.EncryptionAlgorithm;
import com.forest.dto.AuthDTO;
import com.forest.dto.AuthEncryptionDTO;
import com.forest.dto.SignatureDTO;
import com.forest.service.AesEncryptionImpl;
import com.forest.service.IEncryption;
import com.forest.service.Sm4EncryptionImpl;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author Administrator
 */
public class SignParamUtil {

    /** 数据加密算法实现 */
    private static final Map<EncryptionAlgorithm, IEncryption> ENCRYPTION_ALGORITHM = new ConcurrentHashMap<>();

    static {
        ENCRYPTION_ALGORITHM.put(EncryptionAlgorithm.SM4, new Sm4EncryptionImpl());
        ENCRYPTION_ALGORITHM.put(EncryptionAlgorithm.AES, new AesEncryptionImpl());
    }

    /**
     * 构建签名参数.
     * @param appId     appid
     * @param extra     extra
     * @return
     */
    public static AuthDTO buildParam(String appId, Object extra) {
        //获取app信息
        SignatureProperties.AppInfo appInfo = EnvironmentHolder.getAppInfo(appId);
        //构建签名参数
        SignatureDTO dto = SignatureDTO.builder()
                .appKey(appInfo.getAppKey())
                .appSecret(appInfo.getAppSecret())
                .appIv(appInfo.getAppIv())
                .timestamp(System.currentTimeMillis() / 1000 + "")
                .extra(extra == null ? "" : JSONUtil.toJsonStr(extra))
                .signatureAlgorithm(appInfo.getSignatureAlgorithm())
                .build();
        //生成签名
        String signature = SignUtil.getInstance().sign(dto);
        //返回签名参数
        return AuthDTO.builder()
                .appKey(appInfo.getAppKey())
                .timestamp(dto.getTimestamp())
                .signature(signature)
                .extra(dto.getExtra())
                .build();
    }

    /**
     * 构建get请求参数.
     * @param dto    签名参数
     * @return
     */
    public static Map<String,Object> buildGetParam(AuthDTO dto) {
        Map<String, Object> params = BeanUtil.beanToMap(dto);
        Object extra = params.getOrDefault("extra", "");
        //判断业务参数是否为空
        if(ObjectUtil.isNotEmpty(extra)) {
            JSONObject jsonObject = JSONUtil.parseObj(extra);
            params.putAll(jsonObject);
        }
        return params;
    }

    /**
     * 构建post加密参数
     * @param appId
     * @param extra
     * @return
     */
    public static AuthEncryptionDTO buildEncryptionParam(String appId, Object extra) {
        //构建authdto
        AuthDTO authDTO = buildParam(appId, extra);
        //获取app信息
        SignatureProperties.AppInfo appInfo = EnvironmentHolder.getAppInfo(appId);
        //构建加密参数
        EncryptionAlgorithm algorithm = EncryptionAlgorithm.getByAlgorithm(StrUtil.isBlank(appInfo.getEncryptionAlgorithm()) ? EnvironmentHolder.getEncryptionAlgorithm() : appInfo.getEncryptionAlgorithm());
        IEncryption encryption = ENCRYPTION_ALGORITHM.getOrDefault(algorithm, new Sm4EncryptionImpl());
        String params = encryption.encryptBase64(JSONUtil.toJsonStr(authDTO));
        AuthEncryptionDTO dto = AuthEncryptionDTO.builder()
                .appKey(authDTO.getAppKey())
                .data(params)
                .build();
        return dto;
    }

    /**
     * 解密参数.
     *
     * @param dto
     * @param secretKey
     * @return
     */
    public static AuthDTO unAuthEncryptionParam(AuthEncryptionDTO dto, String encryptionAlgorithm , String secretKey) {
        EncryptionAlgorithm algorithm = EncryptionAlgorithm.getByAlgorithm(encryptionAlgorithm);
        IEncryption encryption = ENCRYPTION_ALGORITHM.getOrDefault(algorithm, new Sm4EncryptionImpl());
        String dataStr = encryption.decrypt(dto.getData(), secretKey);
        return JSONUtil.toBean(dataStr, AuthDTO.class);
    }

    /**
     * 获取业务参数.
     * @param extra
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getExtParam(String extra, Class<T> clazz) {
        return JSONUtil.toBean(extra, clazz);
    }

    /**
     * 获取业务参数.
     * @param dto
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getExtParam(AuthEncryptionDTO dto, String encryptionAlgorithm , String secretKey, Class<T> clazz) {
        AuthDTO authDTO = unAuthEncryptionParam(dto, encryptionAlgorithm, secretKey);
        return JSONUtil.toBean(authDTO.getExtra(), clazz);
    }
}
